{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "9e083267",
   "metadata": {},
   "source": [
    "# Analyzing and tuning a resonator\n",
    "We will use here the `advanced` EPR method to run the simulation and analysi, which directly controls renderers and external packages. Please refer to the tutorial notebook 4.2 to follow the `suggested` flow to run the analysis."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b0b5c3a4",
   "metadata": {},
   "source": [
    "### Resonator design\n",
    "1. Prepare the single transmon qubit layout in qiskit-metal. <br>\n",
    "\n",
    "### Resonator analysis using EPR method\n",
    "1. Set-up and run a finite element simulate to extract the eigenmode. <br>\n",
    "1. Display EM fields to inspect quality of the setup. <br>\n",
    "1. Calculate EPR of substrate.  <br>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5916c01b",
   "metadata": {},
   "source": [
    "## Prerequisite\n",
    "You need to have a working local installation of Ansys.<br>\n",
    "Also you will need the following directives and inports."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "79675408",
   "metadata": {},
   "outputs": [],
   "source": [
    "%load_ext autoreload\n",
    "%autoreload 2\n",
    "\n",
    "import qiskit_metal as metal\n",
    "from qiskit_metal import designs, draw\n",
    "from qiskit_metal import MetalGUI, Dict, Headings\n",
    "import pyEPR as epr"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9743faca",
   "metadata": {},
   "source": [
    "# 1. Create the Resonator design\n",
    "\n",
    "Fix the design dimensions that you intend to reflect in the design rendering. <br>\n",
    "Note that the design size extends from the origin into the first quadrant."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ffbc7de0",
   "metadata": {},
   "outputs": [],
   "source": [
    "design = designs.DesignPlanar({}, True)\n",
    "design.chips.main.size['size_x'] = '2mm'\n",
    "design.chips.main.size['size_y'] = '2mm'\n",
    "\n",
    "gui = MetalGUI(design)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0badfb73",
   "metadata": {},
   "source": [
    "Create a readout resonator. Here, we define one end of the resonator as a short and the other end as an open. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6dfdf30a",
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit_metal.qlibrary.tlines.meandered import RouteMeander\n",
    "from qiskit_metal.qlibrary.terminations.open_to_ground import OpenToGround\n",
    "from qiskit_metal.qlibrary.terminations.short_to_ground import ShortToGround\n",
    "\n",
    "design.delete_all_components()\n",
    "\n",
    "otg = OpenToGround(design, 'open_to_ground', options=dict(pos_x='1.25mm',  pos_y='0um', orientation='0'))\n",
    "stg = ShortToGround(design, 'short_to_ground', options=dict(pos_x='-1.25mm',  pos_y='0um', orientation='180'))\n",
    "rt_meander = RouteMeander(design, 'readout',  Dict(\n",
    "        total_length='6 mm',\n",
    "        hfss_wire_bonds = True,\n",
    "        fillet='90 um',\n",
    "        lead = dict(start_straight='100um'),\n",
    "        pin_inputs=Dict(\n",
    "            start_pin=Dict(component='short_to_ground', pin='short'),\n",
    "            end_pin=Dict(component='open_to_ground', pin='open')), ))\n",
    "\n",
    "gui.rebuild()\n",
    "gui.autoscale()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "53e0100d",
   "metadata": {},
   "source": [
    "# 2. Analyze the resonator using the Eigenmode-EPR method\n",
    "\n",
    "In this section we will use a semi-manual (advanced) analysis flow. Please refer to tutorial 4.2 for the `suggested` method. As illustrated, the methods are equivalent, but the advanced method allows you to directly override some renderer-specific settings.\n",
    "\n",
    "### Finite Element Eigenmode Analysis\n",
    "\n",
    "#### Setup\n",
    "\n",
    "Select the analysis you intend to run from the `qiskit_metal.analyses` collection.<br>\n",
    "Select the design to analyze and the tool to use for any external simulation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ef435bc8",
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit_metal.analyses.quantization import EPRanalysis\n",
    "eig_res = EPRanalysis(design, \"hfss\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1e56b6f3",
   "metadata": {},
   "source": [
    "For the Eigenmode simulation portion, you can either:\n",
    "1. Use the `eig_res` user-friendly methods (see tutorial 4.2)\n",
    "2. Control directly the simulation tool from the tool's GUI (outside metal - see specific vendor instructions)\n",
    "3. Use the renderer methods\n",
    "In this section we show the advanced method (method 3).\n",
    "\n",
    "The renderer can be reached from the analysis class. Let's give it a shorter alias."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ca17c49d",
   "metadata": {},
   "outputs": [],
   "source": [
    "hfss = eig_res.sim.renderer"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "374fab78",
   "metadata": {},
   "source": [
    "Now we connect to the tool using the unified command."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "463b2ee8",
   "metadata": {},
   "outputs": [],
   "source": [
    "hfss.start()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5b1152ff",
   "metadata": {},
   "source": [
    "The previous command is supposed to open ansys (if closed), create a new project and finally connect this notebook to it.\n",
    "\n",
    "If for any reason the previous cell failed, please try the manual path described in the next three cells:\n",
    "1. uncomment and execute only **one** of the lines in the first cell.\n",
    "1. uncomment and execute the second cell.\n",
    "1. uncomment and execute only **one** of the lines in the third cell."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1ff70277",
   "metadata": {},
   "outputs": [],
   "source": [
    "# hfss.open_ansys()   # this opens Ansys 2021 R2 if present\n",
    "# hfss.open_ansys(path_var='ANSYSEM_ROOT211')\n",
    "# hfss.open_ansys(path='C:\\Program Files\\AnsysEM\\AnsysEM21.1\\Win64')\n",
    "# hfss.open_ansys(path='../../../Program Files/AnsysEM/AnsysEM21.1/Win64')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "92b051b7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# hfss.new_ansys_project()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "289725a9",
   "metadata": {},
   "outputs": [],
   "source": [
    "# hfss.connect_ansys()\n",
    "# hfss.connect_ansys('C:\\\\project_path\\\\', 'Project1')  # will open a saved project before linking the Jupyter session"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bfc6df05",
   "metadata": {},
   "source": [
    "#### Execute simulation and verify convergence\n",
    "\n",
    "Create and activate an eigenmode design called \"Readout\"."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0314c33d",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "hfss.activate_ansys_design(\"Readout\", 'eigenmode')  # use new_ansys_design() to force creation of a blank design"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d8e142c5",
   "metadata": {},
   "source": [
    "Render the resonator called readout in Metal, to \"Readout\" design in Ansys."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "60e6bb4d",
   "metadata": {},
   "outputs": [],
   "source": [
    "hfss.render_design(['short_to_ground', 'readout', 'open_to_ground'], [])\n",
    "hfss.save_screenshot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ddb92c8a",
   "metadata": {},
   "source": [
    "Set the convergence parameters and junction properties in the Ansys design. <br>\n",
    "Then run the analysis and plot the convergence."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5788eeec",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Analysis properties\n",
    "setup = hfss.pinfo.setup\n",
    "setup.passes = 20\n",
    "print(f\"\"\"\n",
    "Number of eigenmodes to find             = {setup.n_modes}\n",
    "Number of simulation passes              = {setup.passes}\n",
    "Convergence freq max delta percent diff  = {setup.delta_f}\n",
    "\"\"\")\n",
    "\n",
    "# Next 2 lines are counterinuitive, since there is no junction in this resonator.\n",
    "# However, these are necessary to make pyEPR work correctly. Please do note delete\n",
    "hfss.pinfo.design.set_variable('Lj', '10 nH')\n",
    "hfss.pinfo.design.set_variable('Cj', '0 fF')\n",
    "\n",
    "setup.analyze()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1697fc3d",
   "metadata": {},
   "source": [
    "To plot the results you can use the `plot_convergences()` method from the `eig_res.sim` object. The method will read the data from the variables local to the `eig_res.sim` object, so we first need to assign the simulation results to these two variables. let's do both (assignment and plotting) in the next cell.\n",
    "\n",
    "Note: if `hfss.get_convergences()` raises a com_error, it is likely due to the simulation not converging. Try increasing the number of passess in the setup above or tweak other simulation or layout parameters."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b2011533",
   "metadata": {},
   "outputs": [],
   "source": [
    "eig_res.sim.convergence_t, eig_res.sim.convergence_f, _ = hfss.get_convergences()\n",
    "eig_res.sim.plot_convergences()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1b0597e0",
   "metadata": {},
   "source": [
    "#### Refine the resonator design, rerun simulation and verify convergence\n",
    "\n",
    "Next, we change the length of the resonator and see how the eigen frequency changes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b18413c1",
   "metadata": {},
   "outputs": [],
   "source": [
    "rt_meander.options.total_length ='9 mm'\n",
    "\n",
    "gui.rebuild()\n",
    "gui.autoscale()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b074732e",
   "metadata": {},
   "source": [
    "Need to render the updated design again. Let's do that in a new design (\"Readout_1\") to avoid conflicts. Alternatively you will need to delete all the shapes from the previous design to be able to re-draw in it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "74356bf4",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "hfss.activate_ansys_design(\"Readout_1\", 'eigenmode')  # use new_ansys_design() to force creation of a blank design"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fd2230ab",
   "metadata": {},
   "outputs": [],
   "source": [
    "hfss.render_design(['short_to_ground','readout', 'open_to_ground'], [])\n",
    "hfss.save_screenshot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1612460c",
   "metadata": {},
   "source": [
    "now re-execute the analysis. We will skip the design variable setup since they are still in memory."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ba15ad33",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Analysis properties\n",
    "setup = hfss.pinfo.setup\n",
    "setup.passes = 20\n",
    "print(f\"\"\"\n",
    "Number of eigenmodes to find             = {setup.n_modes}\n",
    "Number of simulation passes              = {setup.passes}\n",
    "Convergence freq max delta percent diff  = {setup.delta_f}\n",
    "\"\"\")\n",
    "\n",
    "# Next 2 lines are counterinuitive, since there is no junction in this resonator.\n",
    "# However, these are necessary to make pyEPR work correctly. Please do note delete\n",
    "hfss.pinfo.design.set_variable('Lj', '10 nH')\n",
    "hfss.pinfo.design.set_variable('Cj', '0 fF')\n",
    "\n",
    "setup.analyze()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b54d14c8",
   "metadata": {},
   "outputs": [],
   "source": [
    "eig_res.sim.convergence_t, eig_res.sim.convergence_f, _ = hfss.get_convergences()\n",
    "eig_res.sim.plot_convergences()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f575990f",
   "metadata": {},
   "source": [
    "From the above analyses we observe that for a total length of 6 mm for the resonator, the Eigen Frequency was close to 4.9 GHz. However, for a total length of 9 mm, this frequency is close to 3.3 GHz. Similar analysis can be performed by the user for matching a particular frequency of interest."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1788ac2f",
   "metadata": {},
   "source": [
    "#### Plot the EM field for inspection\n",
    "Display the Ansys modeler window and plot the E-field on the chip's surface."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "657bc4de",
   "metadata": {},
   "outputs": [],
   "source": [
    "hfss.modeler._modeler.ShowWindow()\n",
    "hfss.plot_ansys_fields('main')\n",
    "hfss.save_screenshot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "84de21a1",
   "metadata": {},
   "source": [
    "Delete the newly created E-field plot to prepare for the next phase."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2a27666a",
   "metadata": {},
   "outputs": [],
   "source": [
    "hfss.plot_ansys_delete(['Mag_E1'])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6aee85b4",
   "metadata": {},
   "source": [
    "### EPR Analysis\n",
    "In the `suggested` (tutorial 4.2) flow, we would now prepare the setup using `eig_res.setup` and run the analysis with `eig_res.run_epr()`. Notice that this method requires previous set of the `eig_res` variables `convergence_t` and `convergence_f` like we did a thee cells earlier.\n",
    "\n",
    "However we here exemplify the advanced approach, which is Ansys-specific since it uses the pyEPR module methods directly.\n",
    "#### Execute the energy distribution analysis\n",
    "\n",
    "First initialize epr for non-junction analysis. This will set the ground plain to 'main'."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3a0cc4d0",
   "metadata": {},
   "outputs": [],
   "source": [
    "eig_res.epr_start(no_junctions=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fb75b935",
   "metadata": {},
   "source": [
    "Execute microwave analysis on eigenmode solutions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6d7fdb6e",
   "metadata": {},
   "outputs": [],
   "source": [
    "eprd = hfss.epr_distributed_analysis"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4d330e9d",
   "metadata": {},
   "source": [
    "Find the electric and magnetic energy stored in the substrate and the system."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "86329331",
   "metadata": {},
   "outputs": [],
   "source": [
    "ℰ_elec = eprd.calc_energy_electric()\n",
    "ℰ_elec_substrate = eprd.calc_energy_electric(None, 'main')\n",
    "ℰ_mag = eprd.calc_energy_magnetic()\n",
    "\n",
    "print(f\"\"\"\n",
    "ℰ_elec_all       = {ℰ_elec}\n",
    "ℰ_elec_substrate = {ℰ_elec_substrate}\n",
    "EPR of substrate = {ℰ_elec_substrate / ℰ_elec * 100 :.1f}%\n",
    "\n",
    "ℰ_mag    = {ℰ_mag}\n",
    "\"\"\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b54463ef",
   "metadata": {},
   "source": [
    "Release Ansys session"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d03e67f5",
   "metadata": {},
   "outputs": [],
   "source": [
    "eig_res.sim.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e842f1fd",
   "metadata": {},
   "source": [
    "(optional) close the GUI."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "08cd10a4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# gui.main_window.close()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
